# 0 leds
# 1 switches
# 2 seven segs
# this program repeatedly sets off software interrupts and counts them

### KERNEL ###

addi $t0, $0, 0xC        # load ISR PC
mtc0 $t0, $15            # set ebase to ISR

j start                  # go to user code

isr: mfc0 $k0, $13       # load the cause reg (the label is just for description)

and $k1, $k0, $s4        # mask out the software interrupt bit
bne $k0, $0, soft0       # branch to specific handler

eret                     # not handling anything else here

soft0: addi $s3, $s3, 1  # increment interrupt counter register
mfc0 $k0, $13            # load cause register
srl $k0, $k0, 8          # shift over
sw $s3, ($s0)            # put on leds
and $k1, $k1, $s5        # turn off the interrupt
mtc0 $k1, $13            # disable interrupt

eret                     # return from exception

### USER ###

start:
# set up MMIO offsets
lui $s0, 0xFFFF          # leds
ori $s1, $s0, 0x0040     # switches
ori $s2, $s0, 0x0080     # seven segs

addi $t0, $0, 0x0101     # setting bits 8 (first software interrupt) and 0 (interrupt enable)
mtc0 $t0, $12            # set the status register (only status[25:8, 0] is software writable)

add $s3, $0, $0          # initialise interrupt counter

addi $s4, $0, 0x0100     # set mask to for the first software interrupt (1 << 8)

addi $a0, $0, 0
jal wait

addi $a0, $0, 1
jal wait

nor $s5, $s4, $0         # set mask to turn off the first software interrupt

addi $a0, $0, 2
jal wait

addi $s6, $0, 0xFFFFFFFE # set mask to disable interrupts, specify full word for mars' benefit

loop: mfc0 $t0, $12      # load status register
and $t1, $t0, $s6        # set bit 0 low, keep original status word
mtc0 $t1, $12            # set status word, code is now uninterruptable
mfc0 $t1, $13            # load cause register
or $t1, $t1, $s4         # set soft interrupt bit
mtc0 $t1, $13            # set interrupt in cause register, the interrupt is now waiting
mtc0 $t0, $12            # set status word back to what it was, which now sets off the interrupt
#j loop                   # after isr, do it again


# wait for switch subroutine
# uses switches and leds
# switches assumed to be off (at least >= arg)
wait: # parameter $a0 = switch/led [0-7]
addi $a1, $0, 1
sllv $a1, $a1, $a0
sw $a1, ($s0)
wait0: lw $a1, ($s1)
srlv $a1, $a1, $a0
bne $a1, $0, wait1
j wait0
wait1: sw $0, ($s0)
jr $ra
